home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / libs / intuisup.lha / Intuisup / source.lha / Menus / menus.c < prev    next >
C/C++ Source or Header  |  1992-06-03  |  15KB  |  493 lines

  1. /* $Revision Header *** Header built automatically - do not edit! ***********
  2.  *
  3.  *    (C) Copyright 1991 by Torsten Jürgeleit
  4.  *
  5.  *    Name .....: menus.c
  6.  *    Created ..: Thursday 19-Dec-91 18:02:58
  7.  *    Revision .: 2
  8.  *
  9.  *    Date        Author                 Comment
  10.  *    =========   ====================   ====================
  11.  *    03-Jun-92   Torsten Jürgeleit      subitems now indicated by `»',
  12.  *                                         alternate color for item texts,
  13.  *                                         now correct item width calculated
  14.  *                                         in init_menu()
  15.  *    20-Apr-92   Torsten Jürgeleit      Enforcer hit in init_menu -> *key
  16.  *    19-Dec-91   Torsten Jürgeleit      Created this file!
  17.  *
  18.  ****************************************************************************
  19.  *
  20.  *    Menu support routines
  21.  *
  22.  * $Revision Header ********************************************************/
  23.  
  24.     /* Includes */
  25.  
  26. #include <exec/types.h>
  27. #include <exec/memory.h>
  28. #include <intuition/intuition.h>
  29. #ifdef AZTEC_C
  30. #include <functions.h>   /* needed for Aztec C - prototypes and pragmas for all Amiga system functions */
  31. #endif
  32. #include <libraries/memwatch.h>   /* header file for memory debug link library (Fish 240) - AFTER functions.h */
  33. #include <string.h>
  34. #include "/render/render.h"
  35. #include "/language/language.h"
  36. #include "menus.h"
  37.  
  38.     /* Static prototypes */
  39.  
  40. ULONG  get_buffer_size(struct MenuList  *ml);
  41. VOID   get_item_text_pens(struct MenuList  *ml);
  42. BOOL   init_menu(struct MenuList  *ml);
  43. USHORT intui_text_length(BYTE *text, struct TextAttr  *ta);
  44. VOID   equal_select_box_width(struct MenuItem  *item);
  45.  
  46.     /* Static pragmas */
  47.  
  48. #pragma regcall(get_buffer_size(a0))
  49. #pragma regcall(get_item_text_pens(a0))
  50. #pragma regcall(init_menu(a0))
  51. #pragma regcall(intui_text_length(a0,a1))
  52. #pragma regcall(equal_select_box_width(a0))
  53.  
  54.     /* Create menu list */
  55.  
  56.    struct MenuList *
  57. create_menu(struct RenderInfo  *ri, struct Window  *win,
  58.      struct MenuData  *md, struct TextAttr  *ta, BYTE **language_text_array)
  59. {
  60.    if (ri && ri->ri_ID == ISUP_ID && win && md) {
  61.       struct MenuList  *ml;
  62.  
  63.       if (ml = AllocMem((LONG)sizeof(struct MenuList),
  64.                       (LONG)MEMF_PUBLIC | MEMF_CLEAR)) {
  65.      struct TextFont  *tf;
  66.  
  67.      /* Init menu list struct */
  68.      ml->ml_RenderInfo        = ri;
  69.      ml->ml_Window            = win;   /* needed for colors !!! */
  70.      ml->ml_Data              = md;
  71.      ml->ml_TextAttr          = ta;
  72.      ml->ml_LanguageTextArray = language_text_array;
  73.      ml->ml_Flags             = 0;
  74.      ml->ml_ID                = ISUP_ID;
  75.  
  76.      /* Get font for menu texts */
  77.      if (ta) {
  78.         tf = OpenFont(ta);
  79.      } else {
  80.         tf = ri->ri_TextFont;
  81.      }
  82.      if (ml->ml_TextFont = tf) {
  83.         if (ml->ml_BufferSize = get_buffer_size(ml)) {
  84.            if (ml->ml_Buffer = AllocMem(ml->ml_BufferSize,
  85.                       (LONG)MEMF_PUBLIC | MEMF_CLEAR)) {
  86.           get_item_text_pens(ml);
  87.           if (init_menu(ml) == TRUE) {
  88.              return(ml);
  89.           }
  90.           FreeMem(ml->ml_Buffer, ml->ml_BufferSize);
  91.            }
  92.         }
  93.         if (ta) {
  94.            CloseFont(tf);
  95.         }
  96.      }
  97.      FreeMem(ml, (LONG)sizeof(struct MenuList));
  98.       }
  99.    }
  100.    return(NULL);
  101. }
  102.     /* Attach menu list to given window */
  103.  
  104.    VOID
  105. attach_menu(struct Window  *win, struct MenuList  *ml)
  106. {
  107.    if (win && ml && ml->ml_ID == ISUP_ID) {
  108.  
  109.       /* Remove menu strip from old window if any and attach it to new one */
  110.       if (ml->ml_Flags & MENU_LIST_FLAG_ATTACHED) {
  111.      ClearMenuStrip(ml->ml_Window);
  112.       }
  113.       SetMenuStrip(win, (struct Menu *)ml->ml_Buffer);
  114.       ml->ml_Window = win;
  115.       ml->ml_Flags |= MENU_LIST_FLAG_ATTACHED;
  116.    }
  117. }
  118.     /* Return menu item address */
  119.  
  120.    struct MenuItem *
  121. menu_item_address(struct MenuList  *ml, USHORT menu_num)
  122. {
  123.    struct MenuItem  *mi = NULL;
  124.  
  125.    if (ml && ml->ml_ID == ISUP_ID) {
  126.       mi = ItemAddress((struct Menu *)ml->ml_Buffer, (LONG)menu_num);
  127.    }
  128.    return(mi);
  129. }
  130.     /* Remove menu list from window currently attached to */
  131.  
  132.    struct Window *
  133. remove_menu(struct MenuList  *ml)
  134. {
  135.    struct Window  *win = NULL;
  136.  
  137.    if (ml && ml->ml_ID == ISUP_ID) {
  138.       if (ml->ml_Flags & MENU_LIST_FLAG_ATTACHED) {
  139.      win = ml->ml_Window;
  140.      ClearMenuStrip(win);
  141.      ml->ml_Flags &= ~MENU_LIST_FLAG_ATTACHED;
  142.       }
  143.    }
  144.    return(win);
  145. }
  146.     /* Free menu */
  147.  
  148.    VOID
  149. free_menu(struct MenuList  *ml)
  150. {
  151.    if (ml && ml->ml_ID == ISUP_ID) {
  152.       if (ml->ml_Flags & MENU_LIST_FLAG_ATTACHED) {
  153.      ClearMenuStrip(ml->ml_Window);
  154.       }
  155.       if (ml->ml_TextAttr) {
  156.      CloseFont(ml->ml_TextFont);
  157.       }
  158.       FreeMem(ml->ml_Buffer, ml->ml_BufferSize);
  159.       FreeMem(ml, (LONG)sizeof(struct MenuList));
  160.    }
  161. }
  162.     /* Get buffer size for menus, items and intui texts */
  163.  
  164.    STATIC ULONG
  165. get_buffer_size(struct MenuList  *ml)
  166. {
  167.    struct MenuData  *md = ml->ml_Data;
  168.    ULONG buffer_size = 0;
  169.  
  170.    if (md->md_Type != INTUISUP_DATA_END &&
  171.                       md->md_Type == MENU_DATA_TYPE_TITLE) {
  172.       USHORT menus = 0, items = 0, subitem_texts = 0;
  173.       BOOL   error = FALSE, subitem = FALSE;
  174.  
  175.       do {
  176.      switch (md++->md_Type) {
  177.         case MENU_DATA_TYPE_TITLE :
  178.            menus++;
  179.            subitem = FALSE;
  180.            break;
  181.  
  182.         case MENU_DATA_TYPE_ITEM :
  183.            items++;
  184.            subitem = FALSE;
  185.            break;
  186.  
  187.         case MENU_DATA_TYPE_SUBITEM :
  188.            items++;
  189.  
  190.            /* If first subitem then add text with `»' to previous item */
  191.            if (subitem == FALSE) {
  192.           subitem_texts++;
  193.           subitem = TRUE;
  194.            }
  195.            break;
  196.  
  197.         default :
  198.            error = TRUE;
  199.            break;
  200.      }
  201.       } while (error == FALSE && md->md_Type != INTUISUP_DATA_END &&
  202.                      md->md_Type <= MAX_MENU_DATA_TYPE);
  203.       if (error == FALSE && menus && items) {
  204.      buffer_size = menus * sizeof(struct Menu) + items *
  205.               (sizeof(struct MenuItem) + sizeof(struct IntuiText)) +
  206.                    subitem_texts * sizeof(struct IntuiText);
  207.       }
  208.    }
  209.    return(buffer_size);
  210. }
  211.     /* Get two different text pens for items */
  212.  
  213.    STATIC VOID
  214. get_item_text_pens(struct MenuList  *ml)
  215. {
  216.    struct RenderInfo  *ri = ml->ml_RenderInfo;
  217.    SHORT num_colors;
  218.    
  219.    if ((num_colors = 1 << ri->ri_ScreenDepth) > MAX_RENDER_COLORS) {
  220.       num_colors = MAX_RENDER_COLORS;
  221.    }
  222.    if (num_colors < 3) {
  223.  
  224.       /* Set render pens for monochrome screen */
  225.       if (ml->ml_Window->BlockPen) {
  226.      ml->ml_TextPen1 = 0;
  227.      ml->ml_TextPen2 = 0;
  228.       } else {
  229.      ml->ml_TextPen1 = 1;
  230.      ml->ml_TextPen2 = 1;
  231.       }
  232.    } else {
  233.       struct ColorMap  *cmap;
  234.       SHORT i, max_diff, back_color, colors[MAX_RENDER_COLORS],
  235.         pens[MAX_RENDER_COLORS];
  236.  
  237.       /* Get current screen colors */
  238.       Forbid();
  239.       cmap = ml->ml_Window->WScreen->ViewPort.ColorMap;
  240.       for (i = 0; i < num_colors; i++) {
  241.      colors[i] = GetRGB4(cmap, (LONG)i);
  242.      pens[i]   = i;
  243.       }
  244.       Permit();
  245.  
  246.       /* Save normal background color */
  247.       back_color = colors[ml->ml_Window->BlockPen];
  248.  
  249.       /* Set text pen 1 - search color with greatest `difference' to backgound color */
  250.       for (i = 0, max_diff = 0; i < num_colors; i++) {
  251.      SHORT diff;
  252.  
  253.      if ((diff = calc_color_difference(colors[i], back_color)) >
  254.                                  max_diff) {
  255.         max_diff        = diff;
  256.         ml->ml_TextPen1 = pens[i];
  257.      }
  258.       }
  259.  
  260.       /* Set text pen 2 - search color with 2nd greatest `difference' to backgound color */
  261.       for (i = 0, max_diff = 0; i < num_colors; i++) {
  262.      SHORT diff;
  263.  
  264.      if ((diff = calc_color_difference(colors[i], back_color)) >
  265.                    max_diff && pens[i] != ri->ri_TextPen1) {
  266.         max_diff        = diff;
  267.         ml->ml_TextPen2 = pens[i];
  268.      }
  269.       }
  270.    }
  271. }
  272.     /* Initialize menu from menu list */
  273.  
  274.    STATIC BOOL
  275. init_menu(struct MenuList  *ml)
  276. {
  277.    struct RenderInfo  *ri = ml->ml_RenderInfo;
  278.    struct TextFont    *menu_tf = ri->ri_TextFont, *item_tf = ml->ml_TextFont;
  279.    struct TextAttr    *menu_ta = &ri->ri_TextAttr, *item_ta = ml->ml_TextAttr;
  280.    struct MenuData    *md;
  281.    struct Menu        *last_menu, *menu = NULL;        /* MUST be defined OUT of for loop */
  282.    struct MenuItem    *last_item, *last_subitem, *item = NULL;    /* MUST be defined OUT of for loop */
  283.    BYTE  *buffer = ml->ml_Buffer;
  284.    SHORT item_ypos, subitem_xpos, subitem_ypos;        /* MUST be defined OUT of for loop */
  285.    BOOL  success = FALSE, error = FALSE, subitem_flag = FALSE;
  286.  
  287.    /* Init menus and items */
  288.    for (md = ml->ml_Data; md->md_Type != INTUISUP_DATA_END &&
  289.                   md->md_Type <= MAX_MENU_DATA_TYPE; md++) {
  290.       struct IntuiText  *itext;
  291.       USHORT type, flags;
  292.       BYTE   *name, *key;
  293.  
  294.       /* Get data from menu data structure */
  295.       type  = md->md_Type;
  296.       flags = md->md_Flags;
  297.       name  = get_language_text(md->md_Text, ml->ml_LanguageTextArray);
  298.       key   = (!md->md_CommandKey ? NULL :
  299.         get_language_text(md->md_CommandKey, ml->ml_LanguageTextArray));
  300.  
  301.       /* Init structures according to data type */
  302.       switch (type) {
  303.      case MENU_DATA_TYPE_TITLE :
  304.  
  305.         /* Prepare last menu and subitem list */
  306.         if (menu) {
  307.            equal_select_box_width(menu->FirstItem);
  308.         }
  309.         if (subitem_flag == TRUE) {
  310.            equal_select_box_width(last_item->SubItem);
  311.         }
  312.  
  313.         /* Init data for new menu */
  314.         item         = NULL;
  315.         last_item    = NULL;
  316.         last_subitem = NULL;
  317.         item_ypos    = 0;
  318.         subitem_flag = FALSE;
  319.         last_menu    = menu;
  320.         menu         = (struct Menu *)buffer;
  321.         buffer      += sizeof(struct Menu);
  322.  
  323.         /* Init new menu */
  324.         if (last_menu) {
  325.  
  326.            /* If this isn't the first menu then connect it to last menu */
  327.            last_menu->NextMenu = menu;
  328.            menu->LeftEdge      = last_menu->LeftEdge + last_menu->Width +
  329.                               menu_tf->tf_XSize;
  330.         } else {
  331.            menu->LeftEdge = 5;
  332.         }
  333.         menu->Width     = intui_text_length(name, menu_ta) +
  334.                               menu_tf->tf_XSize;
  335.         menu->Height    = menu_tf->tf_YSize;
  336.         menu->Flags     = MIDRAWN | (flags & MENU_DATA_FLAG_DISABLED ?
  337.                                0 : MENUENABLED);
  338.         menu->MenuName  = name;
  339.         menu->FirstItem = (struct MenuItem *)buffer;
  340.         break;
  341.  
  342.      case MENU_DATA_TYPE_ITEM :
  343.      case MENU_DATA_TYPE_SUBITEM :
  344.  
  345.         /* Init item data */
  346.         if (subitem_flag == TRUE) {
  347.            last_subitem = item;
  348.         } else {
  349.            last_item = item;
  350.         }
  351.         item    = (struct MenuItem *)buffer;
  352.         itext   = (struct IntuiText *)(item + 1);
  353.         buffer += sizeof(struct MenuItem) + sizeof(struct IntuiText);
  354.  
  355.         /* Init intui text */
  356.         itext->LeftEdge  = (flags & MENU_DATA_FLAG_ATTRIBUTE ?
  357.                                 CHECKWIDTH : 0);
  358.         itext->TopEdge   = 1;
  359.         itext->FrontPen  = (flags & MENU_DATA_FLAG_TEXT_COLOR2 ?
  360.                      ml->ml_TextPen2 : ml->ml_TextPen1);
  361.         itext->DrawMode  = JAM1;
  362.         itext->ITextFont = item_ta;
  363.         itext->IText     = (UBYTE *)name;
  364.  
  365.         /* Init menu item */
  366.         item->Width         = intui_text_length(name, item_ta) +
  367.                  (key ? COMMWIDTH + 2 * item_tf->tf_XSize : 0) +
  368.             (flags & MENU_DATA_FLAG_ATTRIBUTE ? CHECKWIDTH : 0);
  369.         item->Height        = item_tf->tf_YSize + 1;
  370.         item->Flags         = ITEMTEXT | (key ? COMMSEQ : 0) |
  371.                (flags & MENU_DATA_FLAG_DISABLED ? 0 : ITEMENABLED) |
  372.                   (flags & MENU_DATA_FLAG_HIGH_NONE ? HIGHNONE :
  373.            (flags & MENU_DATA_FLAG_HIGH_BOX ? HIGHBOX : HIGHCOMP)) |
  374.               (flags & MENU_DATA_FLAG_ATTRIBUTE ? CHECKIT : 0) |
  375.                 (flags & MENU_DATA_FLAG_SELECTED ? CHECKED : 0);
  376.         item->MutualExclude = md->md_MutualExclude;
  377.         item->ItemFill      = (APTR)itext;
  378.         item->SelectFill    = (APTR)itext;
  379.         item->Command       = (key ? *key : 0);
  380.         item->NextSelect    = MENUNULL;
  381.  
  382.         /* Insert empty line before item ? */
  383.         if (flags & MENU_DATA_FLAG_EMPTY_LINE) {
  384.            if (type == MENU_DATA_TYPE_SUBITEM) {
  385.           subitem_ypos += item->Height;
  386.            } else {
  387.           item_ypos += item->Height;
  388.            }
  389.         }
  390.         if (type == MENU_DATA_TYPE_SUBITEM) {
  391.            if (subitem_flag == TRUE) {
  392.           last_subitem->NextItem = item;
  393.            } else {
  394.           if (!last_item) {
  395.              error = TRUE;   /* no menu item to attach subitem */
  396.              break;
  397.           } else {
  398.              struct IntuiText  *new_itext,
  399.                        *last_itext = (struct IntuiText *)
  400.                             last_item->ItemFill;
  401.              /* Create intui text for sub item indicator `»' */
  402.              new_itext            = (struct IntuiText *)buffer;
  403.              buffer              += sizeof(struct IntuiText);
  404.              new_itext->TopEdge   = last_itext->TopEdge;
  405.              new_itext->FrontPen  = last_itext->FrontPen;
  406.              new_itext->DrawMode  = JAM1;
  407.              new_itext->ITextFont = item_ta;
  408.              new_itext->IText     = (UBYTE *)"»";
  409.              last_itext->NextText = new_itext;
  410.  
  411.              /* Connect sub item to menu item */
  412.              last_item->Width  += intui_text_length((BYTE *)
  413.                  new_itext->IText, item_ta) + item_tf->tf_XSize;
  414.              last_item->SubItem = item;
  415.              subitem_xpos       = intui_text_length((BYTE *)
  416.                            last_itext->IText, item_ta) +
  417.                   (last_item->Flags & CHECKIT ? CHECKWIDTH : 0);
  418.              subitem_ypos       = 0;
  419.              subitem_flag       = TRUE;
  420.           }
  421.            }
  422.            item->LeftEdge = subitem_xpos;
  423.            item->TopEdge  = subitem_ypos;
  424.            subitem_ypos  += item->Height;
  425.         } else {
  426.            if (last_item) {
  427.           last_item->NextItem = item;
  428.            }
  429.            item->TopEdge = item_ypos;
  430.            item_ypos    += item->Height;
  431.            if (subitem_flag == TRUE) {
  432.  
  433.           /* Prepare last subitem list */
  434.           equal_select_box_width(last_item->SubItem);
  435.           subitem_flag = FALSE;
  436.            }
  437.         }
  438.         break;
  439.       }
  440.    }
  441.    if (error == FALSE && item) {
  442.  
  443.       /* Prepare current menu and subitem list */
  444.       equal_select_box_width(menu->FirstItem);
  445.       if (subitem_flag == TRUE) {
  446.      equal_select_box_width(last_item->SubItem);
  447.       }
  448.       success = TRUE;
  449.    }
  450.    return(success);
  451. }
  452.     /* Calc text length in pixels */
  453.  
  454.    STATIC USHORT
  455. intui_text_length(BYTE *text, struct TextAttr  *ta)
  456. {
  457.    struct IntuiText  itext;
  458.  
  459.    /* Init dummy intui text and return text length */
  460.    itext.IText     = (UBYTE *)text;
  461.    itext.ITextFont = ta;
  462.    return(IntuiTextLength(&itext));
  463. }
  464.     /* Set equal select box width for given menu item list */
  465.  
  466.    STATIC VOID
  467. equal_select_box_width(struct MenuItem  *item)
  468. {
  469.    struct MenuItem  *save_item = item;
  470.    ULONG max_width = 0;
  471.  
  472.    /* Search max width */
  473.    do {
  474.       if (item->Width > max_width) {
  475.      max_width = item->Width;
  476.       }
  477.    } while (item = item->NextItem);
  478.  
  479.    /* Set max width */
  480.    item = save_item;
  481.    do {
  482.       item->Width = max_width;
  483.  
  484.       /* If subitem then calc left edge of subitem indicator `»' */
  485.       if (item->SubItem) {
  486.      struct IntuiText  *itext = ((struct IntuiText *)
  487.                           item->ItemFill)->NextText;
  488.      itext->LeftEdge = max_width - intui_text_length((BYTE *)
  489.                         itext->IText, itext->ITextFont);
  490.       }
  491.    } while (item = item->NextItem);
  492. }
  493.